package com.chenfan.filestore.service;

import com.chenfan.ccp.common.exception.ApiException;
//import com.chenfan.filestore.config.NormalException;
import com.chenfan.filestore.exception.FileStoreCode;
import com.chenfan.filestore.model.MinioMetaInfo;
import com.chenfan.filestore.repository.MinioTemplate;
import com.chenfan.filestore.utils.Base64Util;
import com.chenfan.filestore.vo.FileResult;
import io.minio.ObjectStat;
import org.apache.commons.lang.StringUtils;
import org.apache.tomcat.util.http.fileupload.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.Assert;
import org.springframework.web.util.UriUtils;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.Objects;
import java.util.UUID;

/**
 * 文件服务抽象类
 */
public abstract class AbastractFileService {


    private static final Logger LOGGER = LoggerFactory.getLogger(AbastractFileService.class);
    @Autowired
    private MinioTemplate minioClient;

    /**
     * 查看minio文件是否存在
     *
     * @param filePath
     */
    protected MinioMetaInfo checkAndGetFileInfo(String filePath){
        Assert.notNull(filePath, "ID不能为空");
        try {
            //兼容老系统
            ObjectStat objectStat = null;
            objectStat = getMinioClient().getAllObjectsByPrefix(MinioTemplate.DEFAULT_BUCKETNAME, filePath, false);
            if (objectStat == null) {
                throw new ApiException(FileStoreCode.FILE_NOT_EXIST);
            }
            return dealMinioMetaInfo(objectStat);
        } catch (Exception e) {
            throw new ApiException(FileStoreCode.FILE_NOT_EXIST);
        }
    }

    /**
     * 根据minio文件名获取文件流
     * @param filePath filePath
     * @return
     */
    protected InputStream getInputStream(String filePath){
        final MinioMetaInfo minioMetaInfo = checkAndGetFileInfo(filePath);
        return getMinioClient().getObject(MinioTemplate.DEFAULT_BUCKETNAME, minioMetaInfo.getName());
    }

    protected MinioMetaInfo dealMinioMetaInfo(ObjectStat objectStat) {
        MinioMetaInfo metaInfo = new MinioMetaInfo();
        metaInfo.setLength(objectStat.length());
        metaInfo.setContentType(objectStat.contentType());
        metaInfo.setName(objectStat.name());
        String base64Name = null;
        try {
            base64Name = objectStat.httpHeaders().get(MinioMetaInfo.X_AMZ_META_ORIGNAL_FILE_NAME).get(0);
            System.out.println("Filebase64Name=" + base64Name);
            metaInfo.setOrignalName(Base64Util.isBase64(base64Name) ? Base64Util.decode(base64Name) : base64Name);
        } catch (Exception e) {
            metaInfo.setOrignalName(objectStat.name());
        }
        return metaInfo;
    }

    protected void download(HttpServletResponse response, MinioMetaInfo metaInfo) throws UnsupportedEncodingException {
        response.setContentType(metaInfo.getContentType());
        response.setHeader("Content-disposition", "attachment; filename=\"" +
                UriUtils.encode(metaInfo.getOrignalName()+"\"","UTF-8"));
        response.setHeader("Content-Length", String.valueOf(metaInfo.getLength()));
        OutputStream out = null;
        try {
            out = response.getOutputStream();
            IOUtils.copy(getInputStream(metaInfo.getName()), out);
        } catch (IOException e) {
            LOGGER.error(e.getMessage());
        } finally {
            IOUtils.closeQuietly(out);
        }
        LOGGER.info("文件传输完成,退出方法");
    }

    /**
     * 下载文件接口
     *
     * @param fileResult   文件ID
     * @param response 返回流
     */
    public void download(FileResult fileResult, HttpServletRequest request, HttpServletResponse response) {
        MinioMetaInfo metaInfo = checkAndGetFileInfo(fileResult.getId());
        if(Objects.nonNull(fileResult.getFileName())){
            metaInfo.setOrignalName(fileResult.getFileName());
        }
        downloadFile(request,response, metaInfo);
    }

    /**
     * 下载文件输出文件流 按对应的格式输出
     * @param httpResponse
     * @param metaInfo
     */
    protected void downloadFile(HttpServletRequest request,HttpServletResponse httpResponse, MinioMetaInfo metaInfo) {
        InputStream in = null;
        OutputStream out = null;
        try {
            String newFileName = dealFileNameByBrowser(request,metaInfo.getOrignalName());
            in = getMinioClient().getObject(MinioTemplate.DEFAULT_BUCKETNAME, metaInfo.getName());
            byte[] buf = new byte[1024];
            int length = 0;
            httpResponse.reset();
            httpResponse.setHeader("Content-Disposition", "attachment;filename=\"" + newFileName+"\"");
            httpResponse.setContentType(metaInfo.getContentType());
            httpResponse.setCharacterEncoding("utf-8");
            out = httpResponse.getOutputStream();
            while ((length = in.read(buf)) > 0) {
                out.write(buf, 0, length);
            }
            out.close();
        } catch (Exception ex) {
            LOGGER.info("导出失败：", ex.getMessage());
        } finally {
            closeIn(in);
            closeOut(out);
        }
    }

    /**
     * 根据请求适配下载文件名
     * @param request
     * @param fileName
     * @return
     */
    public String dealFileNameByBrowser(HttpServletRequest request, String fileName){
        String newFileName = fileName;
        try {
            final String userAgent = request.getHeader("USER-AGENT");
            if(StringUtils.contains(userAgent, "MSIE")){//IE浏览器
                newFileName = URLEncoder.encode(fileName,"UTF-8");
            }else if(StringUtils.contains(userAgent, "Mozilla")){//google,火狐浏览器
                newFileName = new String(fileName.getBytes("UTF-8"), "ISO8859-1");
            }else{
                newFileName = URLEncoder.encode(fileName,"UTF-8");//其他浏览器
            }
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }


        return newFileName;
    }


    /**
     * 关闭输入流
     * @param in
     */
    protected void closeIn(InputStream in) {
        if (in != null) {
            try {
                in.close();
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
    }

    /**
     * 关闭输出流
     * @param out
     */
    protected void closeOut(OutputStream out) {
        if (out != null) {
            try {
                out.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }


    public MinioTemplate getMinioClient() {
        return minioClient;
    }

    public void setMinioClient(MinioTemplate minioClient) {
        this.minioClient = minioClient;
    }


}
